package com.sisgh.jefdv1.file;

import lombok.extern.slf4j.Slf4j;

import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Set;

@Slf4j
public class LogFileWriter implements Closeable {
    /**
     * 默认缓冲区大小
     */
    private static final int DEFAULT_BUFFER_SIZE = 4096;

    /**
     * 文件路径
     */
    private static final String path = System.getProperty("user.dir") + "/logs/";
    private static final String filename = "jefd.log";
    private static final Charset CHARSET = Charset.defaultCharset();

    /**
     * 通道选项
     */
    private static final Set<StandardOpenOption> options = Set.of(
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.READ,
            StandardOpenOption.WRITE
    );

    private ByteBuffer bb;
    private FileChannel fc;

    private static final LogFileWriter lfw;

    /**
     * 初始化
     */
    static {
        lfw = new LogFileWriter();
        try {
            lfw.open();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建文件及其目录
     * @return
     * @throws IOException
     */
    private Path createFile() throws IOException {
        Path file = Paths.get(path, filename);

        // 创建目录
        Files.createDirectories(file.getParent());
        // 创建文件
        try {
            Files.createFile(file);
        } catch (IOException e) {
            log.error("{} 文件已存在", filename);
        }

        return file;
    }

    private void open() throws IOException {
        Path file = createFile();
        fc = FileChannel.open(file, options);
        bb = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
    }

    public void write(String msg)  {
        byte[] bytes = msg.getBytes(CHARSET);

        int remaining = bb.remaining();
        if (bytes.length > remaining) {
            try {
                fc.write(bb);
            } catch (IOException e) {
                System.out.println("write error");
                throw new RuntimeException(e);
            }
            bb.clear();
        }

        if (bytes.length > bb.capacity()) {
            try {
                fc.write(ByteBuffer.wrap(bytes));
            } catch (IOException e) {
                System.out.println("write error");
                throw new RuntimeException(e);
            }
            bb.clear();
            return;
        }

        bb.put(bytes);
    }

    public void throwable(Throwable t) {
        StringWriter sw = new StringWriter();
        t.printStackTrace(new PrintWriter(sw));

        String pst = sw.toString();

        write(pst);
    }

    @Override
    public void close() throws IOException {
        fc.close();
    }

    public void flush() throws IOException {
        if (bb.position() > 0) {
            bb.flip();
            fc.write(bb);
            bb.clear();
        }
    }

    public static LogFileWriter writer() {
        return lfw;
    }
}
